home *** CD-ROM | disk | FTP | other *** search
/ Micromanía 92 / CDMM92_1.ISO / SOF 2 SDK / sof2sdk-101.msi / _92D6AC311BB48EBA344BBABC89DA6AB0 / _6F2E697333E14FC28A563242AE10BC2A < prev    next >
Encoding:
Text File  |  2002-06-09  |  16.5 KB  |  625 lines

  1. // Copyright (C) 2001-2002 Raven Software
  2. //
  3. #include "g_local.h"
  4.  
  5. int G_MultipleDamageLocations(int hitLocation);
  6.  
  7. #define    MISSILE_PRESTEP_TIME    50
  8.  
  9. /*
  10. ================
  11. G_BounceMissile
  12.  
  13. ================
  14. */
  15. void G_BounceMissile( gentity_t *ent, trace_t *trace ) 
  16. {
  17.     vec3_t    velocity;
  18.     float    dot;
  19.     int        hitTime;
  20.  
  21.     // nothing to do if already stationary
  22.     if ( ent->s.pos.trType == TR_STATIONARY )
  23.     {
  24.         return;
  25.     }
  26.  
  27.     // reflect the velocity on the trace plane
  28.     hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction;
  29.     BG_EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity );
  30.     dot = DotProduct( velocity, trace->plane.normal );
  31.     VectorMA( velocity, -2*dot, trace->plane.normal, ent->s.pos.trDelta );
  32.  
  33.     if ( ent->s.eFlags & EF_BOUNCE_HALF ) 
  34.     {
  35.         VectorScale( ent->s.pos.trDelta, 0.65, ent->s.pos.trDelta );
  36.         // check for stop
  37.         if ( trace->plane.normal[2] > 0.2 && VectorLength( ent->s.pos.trDelta ) < 40 ) 
  38.         {
  39.             G_SetOrigin( ent, trace->endpos );
  40.             return;
  41.         }
  42.     }
  43.     else if ( ent->s.eFlags & EF_BOUNCE_SCALE ) 
  44.     {
  45.         // IF it hit a client then barely bounce off of them since they are "soft"
  46.         if ( trace->entityNum < MAX_CLIENTS )
  47.         {
  48.             VectorScale( ent->s.pos.trDelta, 0.04f, ent->s.pos.trDelta );
  49.  
  50.             // Make sure the grenade doesnt continuously collide with teh player it hit
  51.             ent->target_ent = &g_entities[trace->entityNum];
  52.         }
  53.         else
  54.         {
  55.             VectorScale( ent->s.pos.trDelta, ent->bounceScale, ent->s.pos.trDelta );
  56.         }
  57.  
  58.         // check for stop
  59.         if ( trace->plane.normal[2] > 0.2 && VectorLength( ent->s.pos.trDelta ) < 40 ) 
  60.         {
  61.             G_SetOrigin( ent, trace->endpos );
  62.  
  63.             if ( ent->parent && ent->parent->client )
  64.             {
  65.                 gentity_t* nearby;
  66.                 
  67.                 // Find someone on the opposite team near wher ethe grenade landed
  68.                 nearby = G_FindNearbyClient ( trace->endpos, ent->parent->client->sess.team==TEAM_RED?TEAM_BLUE:TEAM_RED, 800, NULL );                
  69.  
  70.                 if ( nearby )
  71.                 {
  72.                     // Make sure there is someone around to hear them scream
  73.                     nearby = G_FindNearbyClient ( trace->endpos, nearby->client->sess.team, 800, nearby );                
  74.                     G_VoiceGlobal ( nearby, "grenade", qtrue );
  75.                 }
  76.             }
  77.  
  78.             return;
  79.         }
  80.      }
  81.  
  82.     VectorAdd( ent->r.currentOrigin, trace->plane.normal, ent->r.currentOrigin);
  83.     VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase );
  84.     ent->s.pos.trTime = level.time;
  85.  
  86.     G_AddEvent( ent, EV_GRENADE_BOUNCE, trace->surfaceFlags& MATERIAL_MASK );
  87. }
  88.  
  89. /*
  90. ================
  91. G_ExplodeMissile
  92.  
  93. Explode a missile without an impact
  94. ================
  95. */
  96. void G_ExplodeMissile( gentity_t *ent ) {
  97.     vec3_t        dir;
  98.     vec3_t        origin;
  99.  
  100.     BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
  101.     SnapVector( origin );
  102.     G_SetOrigin( ent, origin );
  103.  
  104.     // we don't have a valid direction, so just point straight up
  105.     dir[0] = dir[1] = 0;
  106.     dir[2] = 1;
  107.  
  108.     ent->s.eType = ET_GENERAL;
  109.     G_AddEvent( ent, EV_MISSILE_MISS, (DirToByte( dir ) << MATERIAL_BITS) | MATERIAL_NONE);
  110.  
  111.     ent->freeAfterEvent = qtrue;
  112.  
  113.     // All grenade explosions are now broadcast to ensure that fire and smoke is always seen
  114.     ent->r.svFlags |= SVF_BROADCAST;
  115.  
  116.     // splash damage
  117.     if ( ent->splashDamage ) 
  118.     {
  119.         if (ent->dflags & DAMAGE_AREA_DAMAGE)
  120.         {    
  121.             // do damage over time rather than instantly
  122.             G_CreateDamageArea ( ent->r.currentOrigin, ent->parent, ent->splashDamage*0.05f,ent->splashRadius, 8000,ent->methodOfDeath );
  123.  
  124.             // do some instant damage
  125.             G_RadiusDamage( ent->r.currentOrigin, ent->parent, ent->damage, ent->splashRadius, ent, 
  126.                             1, ent->dflags, ent->splashMethodOfDeath );
  127.         }
  128.         else
  129.         {    // normal radius of effect damage
  130.             G_RadiusDamage( ent->r.currentOrigin, ent->parent, ent->splashDamage, ent->splashRadius, ent, 
  131.                             1, ent->dflags, ent->splashMethodOfDeath );
  132.         }
  133.     }
  134.  
  135.     trap_LinkEntity( ent );
  136. }
  137.  
  138. /*
  139. ================
  140. G_GrenadeThink
  141.  
  142. Marks the grenade ready to explode
  143. ================
  144. */
  145. void G_GrenadeThink ( gentity_t* ent )
  146. {
  147.     ent->s.eFlags |= EF_EXPLODE;
  148. }
  149.  
  150. void G_RunStuckMissile( gentity_t *ent )
  151. {
  152.     if ( ent->takedamage )
  153.     {
  154.         if ( ent->s.groundEntityNum >= 0 && ent->s.groundEntityNum < ENTITYNUM_WORLD )
  155.         {
  156.             gentity_t *other = &g_entities[ent->s.groundEntityNum];
  157.  
  158.             if ( (!VectorCompare( vec3_origin, other->s.pos.trDelta ) && other->s.pos.trType != TR_STATIONARY) || 
  159.                 (!VectorCompare( vec3_origin, other->s.apos.trDelta ) && other->s.apos.trType != TR_STATIONARY) )
  160.             {//thing I stuck to is moving or rotating now, kill me
  161.                 G_Damage( ent, other, other, NULL, NULL, 99999, 0, MOD_CRUSH, HL_NONE );
  162.                 return;
  163.             }
  164.         }
  165.     }
  166.     // check think function
  167.     G_RunThink( ent );
  168. }
  169.  
  170. /*
  171. ================
  172. G_BounceProjectile
  173. ================
  174. */
  175. void G_BounceProjectile( vec3_t start, vec3_t impact, vec3_t dir, vec3_t endout ) {
  176.     vec3_t v, newv;
  177.     float dot;
  178.  
  179.     VectorSubtract( impact, start, v );
  180.     dot = DotProduct( v, dir );
  181.     VectorMA( v, -2*dot, dir, newv );
  182.  
  183.     VectorNormalize(newv);
  184.     VectorMA(impact, 8192, newv, endout);
  185. }
  186.  
  187.  
  188. /*
  189. ================
  190. G_CreateMissile
  191. ================
  192. */
  193. gentity_t* G_CreateMissile( vec3_t org, vec3_t dir, float vel, int life, gentity_t *owner, attackType_t attack  )
  194. {
  195.     gentity_t    *missile;
  196.  
  197.     missile = G_Spawn();
  198.     
  199.     missile->nextthink = level.time + life;
  200.     missile->think = G_FreeEntity;
  201.     missile->s.eType = ET_MISSILE;
  202.     missile->r.svFlags = SVF_USE_CURRENT_ORIGIN;
  203.     missile->parent = owner;
  204.     missile->r.ownerNum = owner->s.number;
  205.  
  206.     if ( attack == ATTACK_ALTERNATE )
  207.     {
  208.         missile->s.eFlags |= EF_ALT_FIRING;
  209.     }
  210.  
  211.     missile->s.pos.trType = TR_LINEAR;
  212.     missile->s.pos.trTime = level.time;// - MISSILE_PRESTEP_TIME;    // NOTENOTE This is a Quake 3 addition over JK2
  213.     missile->target_ent = NULL;
  214.  
  215.     SnapVector(org);
  216.     VectorCopy( org, missile->s.pos.trBase );
  217.     VectorScale( dir, vel, missile->s.pos.trDelta );
  218.     VectorCopy( org, missile->r.currentOrigin);
  219.     SnapVector(missile->s.pos.trDelta);
  220.  
  221.     return missile;
  222. }
  223.  
  224. /*
  225. ================
  226. G_CauseAreaDamage
  227. ================
  228. */
  229. void G_CauseAreaDamage( gentity_t *ent ) 
  230. {
  231.     G_RadiusDamage ( ent->r.currentOrigin, ent->parent, ent->splashDamage, ent->splashRadius, ent, 3, DAMAGE_NO_TEAMKILL, ent->methodOfDeath );
  232.  
  233.     ent->s.time2--;
  234.  
  235.     if ( ent->s.time2 <= 0 )
  236.     {    
  237.         G_FreeEntity ( ent );
  238.         return;
  239.     }
  240.  
  241.     ent->nextthink = level.time + 350;
  242.     trap_LinkEntity( ent );
  243. }
  244.  
  245. /*
  246. ================
  247. G_CreateDamageArea
  248. ================
  249. */
  250. gentity_t* G_CreateDamageArea ( vec3_t origin, gentity_t* attacker, float damage, float radius, int duration, int mod )
  251. {
  252.     gentity_t    *damageArea;
  253.  
  254.     damageArea = G_Spawn();
  255.     
  256.     damageArea->nextthink = level.time + 350;
  257.     damageArea->think = G_CauseAreaDamage;
  258.     damageArea->s.eType = ET_DAMAGEAREA;
  259.     damageArea->r.svFlags = SVF_USE_CURRENT_ORIGIN;
  260.     damageArea->parent = attacker;
  261.     damageArea->r.ownerNum = attacker->s.number;
  262.  
  263.     damageArea->s.pos.trType = TR_STATIONARY;
  264.     damageArea->s.pos.trTime = level.time;
  265.     damageArea->s.time2 = duration / 350;
  266.     damageArea->target_ent = NULL;
  267.  
  268.     damageArea->classname = "DamageArea";
  269.  
  270.     VectorSet( damageArea->r.maxs, 1, 1, 1 );
  271.     VectorScale( damageArea->r.maxs, -1, damageArea->r.mins );
  272.  
  273.     damageArea->splashDamage = damage;
  274.     damageArea->splashRadius = radius;
  275.     damageArea->methodOfDeath = mod;
  276.  
  277.     damageArea->dflags = DAMAGE_RADIUS;
  278.     damageArea->clipmask = MASK_SHOT;
  279.  
  280.     VectorCopy( origin, damageArea->s.pos.trBase );
  281.     VectorCopy( origin, damageArea->r.currentOrigin);
  282.     SnapVector( damageArea->r.currentOrigin  );
  283.  
  284.     return damageArea;
  285. }
  286.  
  287. /*
  288. ================
  289. G_MissileImpact
  290. ================
  291. */
  292. extern gentity_t *CreateWeaponPickup(vec3_t pos,weapon_t weapon);
  293. extern int G_GetHitLocation(gentity_t *target, vec3_t ppoint, vec3_t dir );
  294. void G_MissileImpact( gentity_t *ent, trace_t *trace ) 
  295. {
  296.     gentity_t        *other;
  297.     vec3_t    velocity;
  298.     int d;
  299.     other = &g_entities[trace->entityNum];
  300.  
  301.     d = 0;
  302.  
  303.     // check for bounce
  304.     if ( ( ent->s.eFlags & ( EF_BOUNCE | EF_BOUNCE_HALF | EF_BOUNCE_SCALE ) ) ) 
  305.     {
  306.         G_BounceMissile( ent, trace );
  307.         return;
  308.     }
  309.     
  310.     // impact damage
  311.     if (other->takedamage)
  312.     {
  313.         // FIXME: wrong damage direction?
  314.         BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, velocity );
  315.         if ( VectorLength( velocity ) == 0 )
  316.         {
  317.             velocity[2] = 1;    // stepped on a grenade
  318.         }
  319.         if ( ent->damage )
  320.         {
  321.             int location;
  322.  
  323.             location = HL_NONE;
  324.             if ( other->client )
  325.             {
  326.                 VectorNormalize ( velocity );
  327.                 location = G_GetHitLocation ( other, ent->r.currentOrigin, velocity );
  328.                 if ( ent->splashDamage ) 
  329.                 {
  330.                     location = G_MultipleDamageLocations(location);
  331.                 }
  332.             }
  333.         
  334.             d = G_Damage(other, ent, &g_entities[ent->r.ownerNum], velocity, 
  335.                      ent->s.origin, ent->damage, ent->dflags, 
  336.                      ent->methodOfDeath, location );
  337.  
  338.             if ( d && other->client )
  339.             {
  340.                 gentity_t *tent;
  341.                 vec3_t hitdir;
  342.  
  343.                 // Put some procedural gore on the target.
  344.                 tent = G_TempEntity( ent->r.currentOrigin, EV_EXPLOSION_HIT_FLESH );
  345.                 
  346.                 // send entity and direction
  347.                 VectorSubtract(other->r.currentOrigin, ent->r.currentOrigin, hitdir);
  348.                 VectorNormalize(hitdir);
  349.                 tent->s.eventParm = DirToByte( hitdir );
  350.                 tent->s.otherEntityNum2 = other->s.number;            // Victim entity number
  351.  
  352.                 // Pack the shot info into the temp end for gore
  353.                 tent->s.time  = ent->s.weapon + ((((int)other->s.apos.trBase[YAW]&0x7FFF) % 360) << 16);        
  354.                 if ( ent->s.eFlags & EF_ALT_FIRING )
  355.                 {
  356.                     tent->s.time += (ATTACK_ALTERNATE<<8);
  357.                 }
  358.  
  359.                 VectorCopy ( other->r.currentOrigin, tent->s.angles );
  360.                 SnapVector ( tent->s.angles );
  361.             }
  362.         }
  363.     }
  364.  
  365.     // is it cheaper in bandwidth to just remove this ent and create a new
  366.     // one, rather than changing the missile into the explosion?
  367.  
  368.     if ( d && other->client ) 
  369.     {
  370.         G_AddEvent( ent, EV_MISSILE_HIT, 
  371.                     (DirToByte( trace->plane.normal ) << MATERIAL_BITS) | (trace->surfaceFlags & MATERIAL_MASK));
  372.         ent->s.otherEntityNum = other->s.number;
  373.         if( ent->damage )
  374.         {
  375.             // FIXME: might be able to use the value from inside G_Damage to avoid recalc???
  376.             ent->s.otherEntityNum2 = G_GetHitLocation ( other, g_entities[ent->r.ownerNum].r.currentOrigin, velocity );
  377.         }
  378.     } 
  379.     else 
  380.     {
  381.         G_AddEvent( ent, EV_MISSILE_MISS, 
  382.                     (DirToByte( trace->plane.normal ) << MATERIAL_BITS) | (trace->surfaceFlags & MATERIAL_MASK));
  383.  
  384.         // If missile should stick into impact point (e.g. a thrown knife).
  385.         if(!Q_stricmp(ent->classname,"Knife"))
  386.         {
  387.             // Create a pickup where we impacted.
  388.             vec3_t        pickupPos;
  389.             gentity_t    *pickupEnt;
  390.  
  391.             VectorMA(trace->endpos,1,trace->plane.normal,pickupPos);
  392.  
  393.             pickupEnt=CreateWeaponPickup(pickupPos,WP_KNIFE);
  394.             if(pickupEnt)
  395.             {
  396.                 vec3_t knifeDir,knifeAngles;
  397.  
  398.                 BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, knifeDir );
  399.  
  400.                 //FIXME: needs work to set model angles!
  401.                 VectorNormalize ( knifeDir );
  402.                 vectoangles(knifeDir,knifeAngles);
  403.                 knifeAngles[YAW] += 90;
  404.                 knifeAngles[ROLL] = knifeAngles[PITCH];
  405.                 knifeAngles[PITCH] = 0;
  406.  
  407.                 pickupEnt->s.angles[0]=knifeAngles[0];
  408.                 pickupEnt->s.angles[1]=knifeAngles[1];
  409.                 pickupEnt->s.angles[2]=knifeAngles[2];
  410.  
  411.                 pickupEnt->think = G_FreeEntity;
  412.                 pickupEnt->nextthink = level.time + 30000;  // Stick around for 30 seconds
  413.  
  414.                 pickupEnt->count = 1;
  415.     
  416.                 pickupEnt->s.eFlags |= EF_ANGLE_OVERRIDE;
  417.                 VectorCopy(pickupEnt->s.angles,pickupEnt->r.currentAngles);
  418.                 VectorCopy(pickupEnt->s.angles,pickupEnt->s.apos.trBase);
  419.                 pickupEnt->s.pos.trType=TR_STATIONARY;
  420.                 pickupEnt->s.apos.trTime=level.time;
  421.                 pickupEnt->clipmask = ent->clipmask;
  422.                 pickupEnt->s.groundEntityNum = trace->entityNum;
  423.                 trap_LinkEntity(pickupEnt);            
  424.             }
  425.         }
  426.     }
  427.  
  428.     ent->freeAfterEvent = qtrue;
  429.  
  430.     // All grenade explosions are now broadcast to ensure that fire and smoke is always seen
  431.     ent->r.svFlags |= SVF_BROADCAST;
  432.  
  433.     // change over to a normal entity right at the point of impact
  434.     ent->s.eType = ET_GENERAL;
  435.  
  436.     SnapVectorTowards( trace->endpos, ent->s.pos.trBase );    // save net bandwidth
  437.  
  438.     G_SetOrigin( ent, trace->endpos );
  439.  
  440.     // splash damage (doesn't apply to person directly hit)
  441.     if ( ent->splashDamage ) 
  442.     {
  443.         if (ent->dflags & DAMAGE_AREA_DAMAGE)
  444.         {    
  445.             // do damage over time rather than instantly
  446.             G_CreateDamageArea ( trace->endpos, ent->parent, ent->splashDamage*0.10f,ent->splashRadius*2, 8000,ent->methodOfDeath );
  447.  
  448.             // do some instant damage
  449.             G_RadiusDamage( trace->endpos, ent->parent, ent->damage, ent->splashRadius, other, 
  450.                             1, ent->dflags, ent->splashMethodOfDeath );
  451.         }
  452.         else
  453.         {    // normal radius of effect damage
  454.             G_RadiusDamage( trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius, 
  455.                             other, 1, ent->dflags, ent->splashMethodOfDeath );
  456.         }
  457.     }
  458.  
  459.     trap_LinkEntity( ent );
  460. }
  461.  
  462. /*
  463. ================
  464. G_RunMissile
  465. ================
  466. */
  467. void G_RunMissile( gentity_t *ent ) 
  468. {
  469.     vec3_t        origin;
  470.     trace_t        tr;
  471.     int            passent;
  472.  
  473.     // get current position
  474.     BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
  475.  
  476.     // if this missile bounced off an invulnerability sphere
  477.     if ( ent->target_ent ) 
  478.     {
  479.         passent = ent->target_ent->s.number;
  480.     }
  481.     else 
  482.     {
  483.         // ignore interactions with the missile owner
  484.         passent = ent->r.ownerNum;
  485.     }
  486.  
  487.     // Special case where the grenade has gone up into the sky
  488.     if ( ent->s.eFlags & EF_INSKY )
  489.     {
  490.         // Check to see if its out of the world on the X,Y plane
  491.         // or below it (above is a special case)
  492.         if ( origin[0] < level.worldMins[0] ||
  493.              origin[1] < level.worldMins[1] ||
  494.              origin[0] > level.worldMaxs[0] ||
  495.              origin[1] > level.worldMaxs[1] ||
  496.              origin[2] < level.worldMins[2]    )
  497.         {
  498.             G_FreeEntity( ent );
  499.             return;
  500.         }
  501.  
  502.         // Above it only kills it if the item has no gravity
  503.         if ( origin[2] > level.worldMaxs[2] && ent->s.pos.trType != TR_GRAVITY && ent->s.pos.trType != TR_LIGHTGRAVITY)
  504.         {
  505.             G_FreeEntity( ent );
  506.             return;                
  507.         }
  508.  
  509.         trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask );
  510.  
  511.         // Hit another sky, must be reentering
  512.         if ( tr.fraction == 1.0f )
  513.         {
  514.             ent->s.eFlags &= ~EF_INSKY;
  515.             VectorCopy ( origin, ent->r.currentOrigin );
  516.         }
  517.  
  518.         VectorCopy ( origin, ent->r.currentOrigin );
  519.         trap_LinkEntity ( ent );
  520.     }
  521.     else
  522.     {
  523.         // Run the same test again because the condition may have changed as a result
  524.         // of the greande falling below the sky again
  525.         // Loop this trace so we can break windows
  526.         while ( 1 )
  527.         {
  528.             // trace a line from the previous position to the current position
  529.             trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, passent, ent->clipmask );
  530.  
  531.             // If its glass then redo the trace after breaking the glass
  532.             if ( tr.fraction != 1 && !Q_stricmp ( g_entities[tr.entityNum].classname, "func_glass" ) )
  533.             {
  534.                 g_entities[tr.entityNum].use ( &g_entities[tr.entityNum], ent, ent );
  535.                 continue;
  536.             }
  537.  
  538.             break;
  539.         }
  540.         
  541.         if ( tr.startsolid || tr.allsolid ) 
  542.         {
  543.             // make sure the tr.entityNum is set to the entity we're stuck in
  544.             trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, ent->r.currentOrigin, passent, ent->clipmask );
  545.             tr.fraction = 0;
  546.         }
  547.         else 
  548.         {
  549.             VectorCopy( tr.endpos, ent->r.currentOrigin );
  550.         }
  551.  
  552.         trap_LinkEntity( ent );
  553.  
  554.         if ( tr.fraction != 1 ) 
  555.         {
  556.             // Hit the sky or moving through something
  557.             if ( tr.surfaceFlags & SURF_NOIMPACT ) 
  558.             {
  559.                 // Dont kill a missle that hits the sky and has gravity
  560.                 if ( tr.surfaceFlags & SURF_SKY )
  561.                 {
  562.                     ent->s.eFlags |= EF_INSKY;
  563.                     ent->r.svFlags |= SVF_BROADCAST;
  564.                     VectorCopy ( origin, ent->r.currentOrigin );
  565.                     trap_LinkEntity( ent );
  566.                 }
  567.                 else
  568.                 {
  569.                     G_FreeEntity( ent );
  570.                     return;                
  571.                 }
  572.             }
  573.             else
  574.             {
  575.                 G_MissileImpact( ent, &tr );
  576.  
  577.                 // Is it time to explode
  578.                 if ( ent->s.eFlags & EF_EXPLODE )
  579.                 {
  580.                     ent->s.eFlags &= (~EF_EXPLODE);
  581.                     G_ExplodeMissile ( ent );
  582.                     return;
  583.                 }
  584.  
  585.                 // Exploded
  586.                 if ( ent->s.eType != ET_MISSILE ) 
  587.                 {
  588.                     return;
  589.                 }
  590.             }
  591.         }
  592.         // Is it time to explode
  593.         else if ( ent->s.pos.trType == TR_STATIONARY && (ent->s.eFlags & EF_EXPLODE) )
  594.         {
  595.             ent->s.eFlags &= (~EF_EXPLODE);
  596.             G_ExplodeMissile ( ent );
  597.             return;
  598.         }
  599.     }
  600.     
  601.     // If this is a knife then reorient its angles
  602.     if ( ent->s.weapon == WP_KNIFE )
  603.     {
  604.         vec3_t vel;
  605.  
  606.         BG_EvaluateTrajectoryDelta( &ent->s.pos, level.time, vel );
  607.         vectoangles( vel, ent->s.angles );
  608.  
  609.         ent->s.angles[YAW] += 90;
  610. //        ent->s.angles[ROLL] = ent->s.angles[PITCH];
  611.         ent->s.angles[ROLL] = 0;
  612.         ent->s.angles[PITCH] = 0;
  613.     }
  614.     
  615.     // check think function after bouncing
  616.     G_RunThink( ent );
  617. }
  618.  
  619.  
  620. //=============================================================================
  621.  
  622.  
  623.  
  624.  
  625.